import { ObjInfo } from '@amcax/base';
import { convertMatrix } from '@amcax/renderer';
import { PickedProduct } from '@app-cad/common/components/pick-input/pick-product';
import { pickedProductData } from '@app-cad/common/components/pick-input/types';
import { CSS2DToggle } from '@app-cad/common/utils';
import { wsApi } from '@app-cad/server';
import { ctx2 } from '../../../../../module';
import { AssemblyPreview } from '../../../types/preview-types';
import { revertLastMatrix4 } from './RefDocUtils';

const css2DToggles: CSS2DToggle[] = [];
const pickedNodes: PickedProduct[] = [];

export function clearArrayCommandPreview() {
  clearToggles();
  clearPickedNodes();
}

function clearToggles() {
  css2DToggles.forEach((toggle) => {
    toggle.destroy();
  });
  css2DToggles.length = 0;
}

function clearPickedNodes() {
  pickedNodes.forEach((pickedNode) => {
    pickedNode.destroy();
  });
  pickedNodes.length = 0;
}

export const onArrayCommandExit = () => {
  clearToggles();
  clearPickedNodes();
  ctx2.cadScene.assisGroup.clear();
  ctx2.viewer.requestRender();
};

let requestSymbol: symbol;

export async function executeArrayCommand(
  props: ObjInfo,
  baseID: string,
  validParams: { [p: string]: any },
  preview: boolean,
  base: pickedProductData,
  skipInstances: boolean,
  skippedIds: number[],
) {
  const requestId = Symbol();
  requestSymbol = requestId;

  ctx2.cadScene.assisGroup.clear();

  const { count, count2, useDir2 } = validParams;
  const maxId = useDir2 ? count * count2 : count;

  const params = {
    ...validParams,
    skipids:
      // only send skippedIds when not previewing, as we need the matrix to place every array instance
      !preview && skipInstances ? skippedIds.filter((id) => id < maxId) : [],
  };

  const executionResult: AssemblyPreview[] =
    props == null
      ? await wsApi.createProductArray(baseID, params, preview)
      : await wsApi.setParams((props as any).dxid, params, preview);

  if (preview && requestSymbol === requestId) {
    executionResult?.forEach?.((data, index: number) => {
      const pickedNode = base.assisObj.cloneSelf();

      const instanceSkipped = skipInstances && skippedIds.includes(index);
      pickedNode.visible = !instanceSkipped;

      revertLastMatrix4(data.dxid, pickedNode);
      if (skipInstances) {
        const toggle = new CSS2DToggle(instanceSkipped, (skipped: boolean) => {
          if (skipped) {
            if (!skippedIds.includes(index)) {
              skippedIds.push(index);
            }
          } else {
            const idIndex = skippedIds.indexOf(index);
            if (idIndex !== -1) {
              skippedIds.splice(idIndex, 1);
            }
          }

          pickedNode.visible = !skipped;
          ctx2.viewer.requestRender();
        });
        toggle.addTo(pickedNode);
        css2DToggles.push(toggle);
      }

      pickedNode.applyMatrix4(convertMatrix(data.matrix));
      if (props) {
        // apply the base matrix while editing
        pickedNode.applyMatrix4(convertMatrix((props as any).matrix));
      }

      pickedNodes.push(pickedNode);
    });

    ctx2.cadScene.assisGroup.add(...pickedNodes);
    ctx2.viewer.requestRender();
  }
}
